#include "ConcurrentAlloc.h"

void alloc1()
{
	for (int i = 0; i < 5; ++i)
	{
		void* ptr = ConcurrentAlloc(6);
	}
}

void alloc2()
{
	for (int i = 0; i < 5; ++i)
	{
		void* ptr = ConcurrentAlloc(5);
	}
}

void test_alloc()
{
	std::cout << "Start\n";
	void* ptr1 = ConcurrentAlloc(6);
	void* ptr2 = ConcurrentAlloc(4);
	void* ptr3 = ConcurrentAlloc(7);
	void* ptr4 = ConcurrentAlloc(5);
	void* ptr5 = ConcurrentAlloc(17);
	std::cout << "alloc done\n";

	std::cout << ptr1 << std::endl;
	std::cout << ptr2 << std::endl;
	std::cout << ptr3 << std::endl;
	std::cout << ptr4 << std::endl;
	std::cout << ptr5 << std::endl;

	std::cout << "free start\n";
	ConcurrentFree(ptr1);
	ConcurrentFree(ptr2);
	ConcurrentFree(ptr3);
	ConcurrentFree(ptr4);
	ConcurrentFree(ptr5);

	std::cout << "end\n";
}

void BigAlloc()
{
	void* p1 = ConcurrentAlloc(257*1024);
	ConcurrentFree(p1);
	void* p2 = ConcurrentAlloc(129 * 8 * 1024);
	ConcurrentFree(p2);
}

void test_conFree1()
{
	void* ptr1 = ConcurrentAlloc(5);
	void* ptr2 = ConcurrentAlloc(8);
	void* ptr3 = ConcurrentAlloc(4);
	void* ptr4 = ConcurrentAlloc(6);
	void* ptr5 = ConcurrentAlloc(3);
	void* ptr6 = ConcurrentAlloc(3);
	void* ptr7 = ConcurrentAlloc(3);

	ConcurrentFree(ptr1);
	ConcurrentFree(ptr2);
	ConcurrentFree(ptr3);
	ConcurrentFree(ptr4);
	ConcurrentFree(ptr5);
	ConcurrentFree(ptr6);
	ConcurrentFree(ptr7);
}


 //ntimes 一轮申请和释放内存的次数
 //nwors 创建线程个数
 //rounds 轮次
double BenchmarkMalloc(size_t ntimes, size_t nworks, size_t rounds)
{
	std::vector<std::thread> vthread(nworks);
	std::atomic<double> malloc_costtime(0);
	std::atomic<double> free_costtime(0);

	for (size_t k = 0; k < nworks; ++k)
	{
		vthread[k] = std::thread([&, k]() 
		{
			std::vector<void*> v;
			v.reserve(ntimes);

			for (size_t j = 0; j < rounds; ++j)
			{
				auto begin1 = std::chrono::steady_clock::now();
				for (size_t i = 0; i < ntimes; i++)
				{
					//v.push_back(malloc(16)); // 每一次申请同一个桶中的块
					v.push_back(malloc((16 + i) % 8192 + 1));// 每一次申请不同桶中的块
				}
				auto end1 = std::chrono::steady_clock::now();

				auto begin2 = std::chrono::steady_clock::now();
				for (size_t i = 0; i < ntimes; i++)
				{
					free(v[i]);
				}
				auto end2 = std::chrono::steady_clock::now();
				v.clear();

				double cnt_alloc = std::chrono::duration_cast<std::chrono::microseconds>(end1 - begin1).count()
					* 1.f * std::chrono::milliseconds::period::num / std::chrono::milliseconds::period::den;
				double cnt_free = std::chrono::duration_cast<std::chrono::microseconds>(end2 - begin2).count()
					* 1.f * std::chrono::milliseconds::period::num / std::chrono::milliseconds::period::den;
				
				malloc_costtime += cnt_alloc;
				free_costtime += cnt_free;
			}
		});
	}

	for (auto& t : vthread)
	{
		t.join();
	}

	std::cout << std::format("{0:d}个线程并发执行{1:d}轮次，每轮次malloc {2:d}次: 花费：{3:.2f} ms\n",
		nworks, rounds, ntimes, malloc_costtime.load());

	std::cout << std::format("{0:d}个线程并发执行{1:d}轮次，每轮次free {2:d}次: 花费：{3:.2f} ms\n",
		nworks, rounds, ntimes, free_costtime.load());

	std::cout << std::format("{0:d}个线程并发malloc&free {1:d}次，总计花费：{2:.2f} ms\n",
		nworks, nworks * rounds * ntimes, malloc_costtime.load() + free_costtime.load());

	return malloc_costtime.load() + free_costtime.load();
}


double BenchmarkConcurrentMalloc(size_t ntimes, size_t nworks, size_t rounds)
{
	std::vector<std::thread> vthread(nworks);
	std::atomic<double> malloc_costtime(0);
	std::atomic<double> free_costtime(0);

	for (size_t k = 0; k < nworks; ++k)
	{
		vthread[k] = std::thread([&]() 
		{
			std::vector<void*> v;
			v.reserve(ntimes);

			for (size_t j = 0; j < rounds; ++j)
			{
				auto begin1 = std::chrono::steady_clock::now();
				for (size_t i = 0; i < ntimes; i++)
				{
					//v.push_back(ConcurrentAlloc(16));
					v.push_back(ConcurrentAlloc((16 + i) % 8192 + 1));
				}
				auto end1 = std::chrono::steady_clock::now();

				auto begin2 = std::chrono::steady_clock::now();
				for (size_t i = 0; i < ntimes; i++)
				{
					ConcurrentFree(v[i]);
				}
				auto end2 = std::chrono::steady_clock::now();
				v.clear();

				double d1 = std::chrono::duration_cast<std::chrono::microseconds>(end1 - begin1).count()
					* 1.f * std::chrono::milliseconds::period::num / std::chrono::milliseconds::period::den;
				double d2 = std::chrono::duration_cast<std::chrono::microseconds>(end2 - begin2).count()
					* 1.f * std::chrono::milliseconds::period::num / std::chrono::milliseconds::period::den;
				malloc_costtime += d1;
				free_costtime += d2;
			}
		});
	}

	for (auto& t : vthread)
	{
		t.join();
	}


	std::cout << std::format("{0:d}个线程并发执行{1:d}轮次，每轮次malloc {2:d}次: 花费：{3:.2f} ms\n",
		nworks, rounds, ntimes, malloc_costtime.load());

	std::cout << std::format("{0:d}个线程并发执行{1:d}轮次，每轮次free {2:d}次: 花费：{3:.2f} ms\n",
		nworks, rounds, ntimes, free_costtime.load());

	std::cout << std::format("{0:d}个线程并发Concurrent alloc&delloc {1:d}次，总计花费：{2:.2f} ms\n",
		nworks, nworks * rounds * ntimes, malloc_costtime.load() + free_costtime.load());

	return malloc_costtime.load() + free_costtime.load();
}


int main()
{
	
	std::cout << sizeof(ThreadCache) << std::endl;
	std::cout << sizeof(Span) << std::endl;
	size_t n = 100000;
	std::cout << "==========================================================" << std::endl;
	// 4个线程，每个线程申请10万次，总共申请40万次
	double s1 = BenchmarkConcurrentMalloc(n, 4, 10);
	std::cout << std::endl << std::endl;

	// 4个线程，每个线程申请10万次，总共申请40万次
	double s2 = BenchmarkMalloc(n, 4, 10);

	std::cout << std::endl;
	std::cout << std::format("tcmalloc 比 malloc 快{0:.2f}倍\n",  s2/s1)<< std::endl;
	
	std::cout << "==========================================================" << std::endl;



	return 0;
}